package de.draufi.tracking;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import de.draufi.logging.myLogger;


public class Wegpunkt {

	private static final SimpleDateFormat sdfLesen = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
	public static final int NORTH = 0;
	public static final int SOUTH = 1;
	public static final int EAST = 2;
	public static final int WEST = 3;
	private static final String[] SphereName = {"N", "S", "E", "W"};
	
	public static final int format_dG = 0;    // Dezimalgrad                    ??,?????      (Standard)
	public static final int format_GMS = 1;   // Grad, Minuten, Sekunden        ??° ??' ??"
	public static final int format_GMdS = 2;  // Grad, Minuten, Dezimalsekunden ??° ??' ??,?"
	public static final int format_GdM = 3;   // Grad, Dezmalminuten            ??° ??,??'
	
	
	private double laenge = 0;       // Länge (lon) in Dezimalgrad
	private double breite = 0;       // Breite (lat) in Dezimalgrad
	private double hoehe = 0;
	private int hemisphere_NS;
	private int hemisphere_EW;
	private Timestamp zeit= null;
	
	@SuppressWarnings("boxing")
	public Wegpunkt(String lon, String lat, String ele, String t ){

		try {
			laenge = Double.valueOf(lon);
			if ((int)laenge >= 0) {
				hemisphere_NS = NORTH;
			} else {
				hemisphere_NS = SOUTH;
			}
			breite = Double.valueOf(lat);
			if (((int)breite >= 0 ) || 
				((int)breite <= 180)) {
				hemisphere_EW = EAST;
			} else {
				hemisphere_EW = WEST;
			}
			hoehe = Double.valueOf(ele);
			zeit = new Timestamp(sdfLesen.parse(t.substring(0, 10) + " " + t.substring(11, 19)).getTime() );
		} catch (NumberFormatException nfe) {
			myLogger.getLog(this.getClass().getName()).severe(nfe.getMessage());
		} catch (ParseException pe) {
			myLogger.getLog(this.getClass().getName()).severe(pe.getMessage());
		}
		myLogger.getLog(this.getClass().getName()).finest("Wegpunkt angelegt.");
	}
	
	public void print(){
		System.out.println("Länge  (Longitude) : " + laenge + " (" + SphereName[hemisphere_NS] + ")");
		System.out.println("Breite (Latitude)  : " + breite + " (" + SphereName[hemisphere_EW] + ")");
		System.out.println("Höhe   (Elevation) : " + hoehe);
	}
	
	@SuppressWarnings("boxing")
	public String toString(int format){
		String result = "";
		SimpleDateFormat sdf1 = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss z");
		
		result = "Lon=" + format(laenge, format) + "(" + SphereName[hemisphere_NS] + ") / " +
				 "Lat=" + format(breite, format) + "(" + SphereName[hemisphere_EW] + ") / " +
				 sdf1.format(zeit.getTime());
		
		return result;
	}
	
	private static String format(double d, int format) {
		String result = "";
		DecimalFormat df_00 = new DecimalFormat("#0");
		DecimalFormat df_00_0 = new DecimalFormat("#0.0");
		DecimalFormat df_00_00 = new DecimalFormat("#0.00");
		DecimalFormat df_00_000000 = new DecimalFormat("#0.000000");
		
		switch (format) {
			case format_dG: {
				result = df_00_000000.format(d); 
				break;
			}
			case format_GdM: {
				int g = (int) d;
				double dm = ((d-g)*60);
				result = df_00.format(g) + "°" + df_00_00.format(dm) + "' "; 
				break;
			}
			case format_GMdS: {
				int g = (int) d;
				double dm = ((d-g)*60);
				int m = (int) dm;
				double ds = (dm-m);
				result = df_00.format(g) + "°" + df_00.format(m) + "'" + df_00_0.format(ds) + "\" "; 
				break;
			}
			case format_GMS: {
				int g = (int) d;
				double dm = ((d-g)*60);
				int m = (int) dm;
				double ds = (dm-m);
				int s = (int) ds;
				result = df_00.format(g) + "°" + df_00.format(m) + "'" + df_00.format(s) + "\" "; 
				break;
			}
			default: {
				myLogger.getLog("de.draufi.tracking.Wegpunkt").warning("unknown format: " + format);
				break;
			}
		}
		
		return result;
	}
	
	@Override
	@SuppressWarnings("boxing")
	public String toString() {
		String result = "";
		SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss z");
		
		result = "Lon=" + laenge + "(" + SphereName[hemisphere_NS] + ") / " +
				 "Lat=" + breite + "(" + SphereName[hemisphere_EW] + ") / " +
				 sdf1.format(zeit.getTime());
		
		return result;
	}

	public String getLon() {
		return "" + laenge;
	}

	public String getLat() {
		return "" + breite;
	}


	/**
	 * Liefert den Abstand zum übergebenen Punkt in km
	 * @param endpunkt zu dem der Abstand berechnet wird
	 * @return Abstand in km 
	 */
	public double getDistance(Wegpunkt endpunkt) {
		double lat = (this.breite + endpunkt.breite) / 2 * 0.01745;
		double dx = 111.3 * Math.cos(lat) * (this.laenge - endpunkt.laenge);
		double dy = 111.3 * (this.breite - endpunkt.breite);
		double d = Math.sqrt(dx*dx + dy*dy); //in km
		
		return d;
	}
	
	/**
	 * Liefert die Zeitspanne zum übergebenen Punkt
	 * @param endpunkt zu dem die Dauer ermittelt wird
	 * @return Dauer in Millisekunden
	 */
	public long getDuration(Wegpunkt endpunkt) {
		long result = endpunkt.zeit.getTime() - this.zeit.getTime();
		return result;
	}
	
	/**
	 * Liefert die Geschwindigkeit aus Strecke / Zeit  
	 * @param endpunkt zu dem die Geschwindigkeit ermittelt wird
	 * @return Geschwindigkeit in km/Millisekunden
	 */
	public double getSpeed(Wegpunkt endpunkt) {
		long dur = getDuration(endpunkt);
		double result = 0;
		if (dur != 0) {
			result = getDistance(endpunkt) / dur;
		} else {
			result = 0;
		}
		return result; 
	}
	
	/**
	 * Liefert eine "sprachliche" Abstandsangabe 
	 * @param distance in km
	 * @return Abstand in "passender" Maßeinheit 
	 */
	public static String getDistanceStr(double distance) {
		DecimalFormat df = new DecimalFormat("#0.0000");
		String result = "";
		if (distance < 1) {
			result = df.format(distance*1000) + " m";
		} else {
			result = df.format(distance) + " km";
		}
		return result;
	}
	
	/**
	 * Liefert die Zeitspanne zum übergebenen Punkt im Format "hh:mm:ss"
	 * @param duration in Millisekunden
	 * @return Dauer in hh:mm:ss
	 */
	public static String getDurationStr(long duration) {
		DecimalFormat df = new DecimalFormat("00");
		long d = duration/1000;
		long rest = d;
		double dh = (d/(60*60));
		int h = (int) dh;
		rest = d-(h*60*60);
		double dm = (rest/60);
		int m = (int) dm;
		rest = rest-(m*60);
		double ds = rest;
		int s = (int) ds;
		
		String result = df.format(h) + ":" + df.format(m) + ":" + df.format(s);
		
		return result;
	}

	/**
	 * Liefert die Geschwindigkeit aus Strecke / Zeit in km/h
	 * @param speed in km/millisekunden
	 * @return Geschwindigkeit in km/h
	 */
	public static String getSpeedStr(double speed) {
		return new DecimalFormat("0.000").format(speed*1000*60*60) + " km/h";
	}

	/**
	 * Liefert die Pace in min/km
	 * @param speed in km/millisekunden
	 * @return Pace in min/km
	 */
	public static String getPaceStr(double speed) {
		String result = "";
		if (speed != 0) {
			result = new DecimalFormat("0.00").format(1/(speed*1000*60)) + " min/km";
		} else {
			result = new DecimalFormat("0.00").format(0) + " min/km";
		}
		return result;
	}
	
	
}
